package com.youxin.admin.pay.service.impl;

import cn.hutool.system.UserInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youxin.admin.pay.client.dto.AgentStaticDto;
import com.youxin.admin.pay.client.dto.SystemSettlementDto;
import com.youxin.admin.pay.client.req.AgentStaticSearch;
import com.youxin.admin.pay.entity.req.*;
import com.youxin.admin.pay.entity.vo.*;
import com.youxin.admin.pay.mapper.*;
import com.youxin.admin.pay.model.*;
import com.youxin.admin.pay.service.OrderService;
import com.youxin.admin.pay.service.rpc.RemotePayService;
import com.youxin.base.BaseResultCode;
import com.youxin.base.PageDto;
import com.youxin.base.TPage;
import com.youxin.chat.pay.enums.FeeTypeEnum;
import com.youxin.chat.pay.enums.OrderSourceEnum;
import com.youxin.chat.user.dto.UserInfoDto;
import com.youxin.exception.SystemException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * description: OrderServiceImpl <br>
 * date: 2020/3/5 10:57 <br>
 * author: llkj <br>
 * version: 1.0 <br>
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private UserCashMapper userCashMapper;

    @Resource
    private TransactionDetailMapper transactionDetailMapper;

    @Resource
    private CommonOrderMapper commonOrderMapper;

    @Resource
    private RedReceiveMapper redReceiveMapper;

    @Resource
    private UserTransferMapper userTransferMapper;

    @Resource
    private RedSendMapper redSendMapper;

    @Resource
    private UserRechargeMapper userRechargeMapper;

    @Resource
    private ChannelCashMapper channelCashMapper;

    @Resource
    private ChannelOrderMapper channelOrderMapper;

    @Resource
    private RemotePayService remotePayService;

    @Override
    public TPage<UserCashVo> getCashList(UserCashSearchReq req) {
        IPage<UserCashVo> page = userCashMapper.selectCashList(new Page(req.getCurrentPage(), req.getShowCount()), req);
        return TPage.page(page.getRecords(), page.getTotal());
    }

    @Override
    public PageDto<TransactionDetailVo> pageTransactions(TransactionSearchReq req) {
        IPage<TransactionDetailVo> page = transactionDetailMapper.selectListByParam(new Page(req.getCurrentPage(), req.getShowCount()), req);
        BigDecimal userTransAmount = transactionDetailMapper.sumUserTransAmountByParam(req);
        if (userTransAmount == null) {
            userTransAmount = new BigDecimal(0);
        }
        PageDto<TransactionDetailVo> pageDto = new PageDto<>();
        pageDto.setRecords(page.getRecords());
        pageDto.setTotal(page.getTotal());
        pageDto.setExt(Optional.ofNullable(userTransAmount).map(String::valueOf).orElse("0"));
        return pageDto;
    }

    @Override
    public PageDto<CommonOrderVo> listCommonOrder(CommonOrderSearchReq search) {
        IPage<CommonOrderVo> page = commonOrderMapper.selectOrderByParam(new Page<>(search.getCurrentPage(), search.getShowCount()), search);
        BigDecimal amount = commonOrderMapper.sumOrderAmountByParam(search);
        PageDto<CommonOrderVo> pageDto = new PageDto<>();
        pageDto.setRecords(page.getRecords());
        pageDto.setTotal(page.getTotal());
        pageDto.setExt(Optional.ofNullable(amount).map(String::valueOf).orElse("0"));
        return pageDto;
    }

    @Override
    public List<RedReceiveVo> getRedReceive(String redId) {
        return redReceiveMapper.selectRedReceive(redId);
    }

    @Override
    public Object getOrderDetail(String orderNo) {
        CommonOrder commonOrder = commonOrderMapper.selectByOrderNo(orderNo);
        if (commonOrder.getOrderSource() == OrderSourceEnum.PAY_CODE_RECEIVE.getStatus()) {
            UserTransfer userTransfer = userTransferMapper.selectOne(new LambdaQueryWrapper<UserTransfer>().eq(UserTransfer::getOrderNo, commonOrder.getOrderNo())
                    .eq(UserTransfer::getFeeType, FeeTypeEnum.IN_MONEY.ordinal()));
            return userTransfer;
        } else if (commonOrder.getOrderSource() == OrderSourceEnum.PAY_CODE_TRANSFER.getStatus()) {
            UserTransfer userTransfer = userTransferMapper.selectById(commonOrder.getOrderNo());
            return userTransfer;
        } else if (commonOrder.getOrderSource() == OrderSourceEnum.RED_RECEIVE.getStatus()) {
            RedReceive redReceive = redReceiveMapper.selectById(commonOrder.getOrderNo());
            RedSend redSend = redSendMapper.selectById(redReceive.getRedId());
            UserInfoDto userInfoDto = remotePayService.selectUserInfo(redSend.getUserNo());
            RedSendVo redSendVo = getRedSendInfo(redSend, userInfoDto);
            //RedReceive redPackReceive = redReceiveMapper.selectById(commonOrder.getOrderNo());
            return redSendVo;
        } else if (commonOrder.getOrderSource() == OrderSourceEnum.RED_SEND.getStatus()) {
            RedPackReceiveDetailVo detail = getRedReceiveInfo(commonOrder.getOrderNo());
            return detail;
        }
        return null;
    }

    @Override
    public TPage<UserRechargeVo> getRechargeList(UserRechargeSearchReq req) {
        IPage<UserRechargeVo> page = userRechargeMapper.selectRechargeList(new Page(req.getCurrentPage(), req.getShowCount()), req);
        return TPage.page(page.getRecords(), page.getTotal());
    }

    @Override
    public PageDto<ChannelCashVo> pageChannelCash(ChannelCashSearch search) {

        IPage<ChannelCashVo> page = channelCashMapper.selectCashByParam(new Page<>(search.getCurrentPage(), search.getShowCount()), search);
        BigDecimal cashAmount = channelCashMapper.sumCashAmountByParam(search);
        PageDto<ChannelCashVo> pageDto = new PageDto<>();
        pageDto.setRecords(page.getRecords());
        pageDto.setTotal(page.getTotal());
        pageDto.setExt(Optional.ofNullable(cashAmount).map(String::valueOf).orElse("0"));
        return pageDto;
    }

    @Override
    public PageDto<ChannelOrderVo> pageChannelOrder(ChannelOrderSearch search) {
        IPage<ChannelOrderVo> page = channelOrderMapper.selectOrderByParam(new Page<>(search.getCurrentPage(), search.getShowCount()), search);
        BigDecimal orderAmount = channelOrderMapper.sumCashAmountByParam(search);
        PageDto<ChannelOrderVo> pageDto = new PageDto<>();
        pageDto.setRecords(page.getRecords());
        pageDto.setTotal(page.getTotal());
        pageDto.setExt(Optional.ofNullable(orderAmount).map(String::valueOf).orElse("0"));
        return pageDto;
    }

    @Override
    public SystemSettlementDto staticChannelOrderData(LocalDateTime startTime, LocalDateTime endTime) {
        return channelOrderMapper.staticOrderData(startTime, endTime);
    }

    @Override
    public SystemSettlementDto staticChannelCashData(LocalDateTime startTime, LocalDateTime endTime) {
        return channelCashMapper.staticCashData(startTime, endTime);
    }

    @Override
    public SystemSettlementDto staticUserCashData(LocalDateTime startTime, LocalDateTime endTime) {
        return userCashMapper.staticCashData(startTime, endTime);
    }

    @Override
    public List<AgentStaticDto> staticAgentTransaction(AgentStaticSearch search) {
        return transactionDetailMapper.staticAgentTransaction(search);
    }

    private RedPackReceiveDetailVo getRedReceiveInfo(String redId) {
        RedSend redSend = redSendMapper.selectById(redId);
        if (redSend == null) {
            throw new SystemException(BaseResultCode.RECORD_NOT_EXISTS, "红包不存在");
        }
        RedPackReceiveDetailVo detail = new RedPackReceiveDetailVo();
        List<RedReceiveVo> list = redReceiveMapper.selectRedReceive(redId);
        String finishTime = Optional.ofNullable(redSend.getFinishTime()).map(item -> item.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).orElse("");
        BigDecimal receiveAmount = new BigDecimal(0);
        receiveAmount = list.stream().map(RedReceiveVo::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        detail.setAmount(redSend.getRedAmount());
        detail.setNum(redSend.getNum());
        detail.setReceiveAmount(receiveAmount);
        detail.setUser(list);
        detail.setTime(finishTime);
        detail.setExpired(redSend.getRedStatus() != 2 ? 0 : 1);
        detail.setRedType(redSend.getRedType());
        return detail;
    }

    private RedSendVo getRedSendInfo(RedSend redSend, UserInfoDto userInfoDto){
        RedSendVo redSendVo = new RedSendVo();
        redSendVo.setUserNo(redSend.getUserNo());
        redSendVo.setNickName(userInfoDto.getNickName());
        redSendVo.setAmount(redSend.getRedAmount());
        redSendVo.setCreateTime(redSend.getCreateTime());
        return redSendVo;
    }
}
